

#ifndef _DESIGN_PATTERN_BEHAVIOR_STRATEGY_STRATEGY_H_
#define _DESIGN_PATTERN_BEHAVIOR_STRATEGY_STRATEGY_H_

namespace strategy {

class Strategy {
 public:
  ~Strategy() { std::cout << "Strategy dtor..." << std::endl; }
  virtual void AlgrithmInterface() = 0;
};

using StrategySptr = std::shared_ptr<Strategy>;

class ConcreteStrategy1 : public Strategy {
 public:
  ConcreteStrategy1() { std::cout << "ConcreteStrategy1 ctor..." << std::endl; }
  ~ConcreteStrategy1() {
    std::cout << "ConcreteStrategy1 dtor..." << std::endl;
  }

  void AlgrithmInterface() override {
    std::cout << "ConcreteStrategy1 AlgrithmInterface..." << std::endl;
  }
};

class ConcreteStrategy2 : public Strategy {
 public:
  ConcreteStrategy2() { std::cout << "ConcreteStrategy2 ctor..." << std::endl; }
  ~ConcreteStrategy2() {
    std::cout << "ConcreteStrategy2 dtor..." << std::endl;
  }

  void AlgrithmInterface() override {
    std::cout << "ConcreteStrategy2 AlgrithmInterface..." << std::endl;
  }
};

//////////////////////////////////////////////////////////////////////////

class Context {
 public:
  Context(StrategySptr strategy_sptr)
      : strategy_sptr_(std::move(strategy_sptr)) {
    std::cout << "Context ctor..." << std::endl;
  }
  ~Context() { std::cout << "Context dtor..." << std::endl; }

  void DoAction() {
    std::cout << "Context DoAction..." << std::endl;
    this->strategy_sptr_->AlgrithmInterface();
  }

 private:
  StrategySptr strategy_sptr_{nullptr};
};

//////////////////////////////////////////////////////////////////////////

void Test() {
  std::cout << std::endl;
  std::cout << "strategy///////////////////////////////////////////////////////"
               "///////////////////"
            << std::endl;
  std::cout << std::endl;

  auto ctx = std::make_shared<Context>(std::make_shared<ConcreteStrategy1>());
  ctx->DoAction();

  ctx = std::make_shared<Context>(std::make_shared<ConcreteStrategy2>());
  ctx->DoAction();
}

}  // namespace strategy

#endif  // _DESIGN_PATTERN_BEHAVIOR_STRATEGY_STRATEGY_H_
